  
--get the addon namespace
local addon, ns = ...
  
--get the config values
local LabelUI = ns.LabelUI
local point = LabelUI.point
local cfg = ns.cfg
local bar
local barcfg
local barspos = {}
local RuneCheck
local statusbar

local function GetCooldown(spell)
	if spell.item then
		return GetItemCooldown(spell.item)
	else
		return GetSpellCooldown(spell.name)
	end
end

local function GetInfo(spell)
	if spell.item then
		local itemName, _, _, _, _, _, _, _, _, itemTexture = GetItemInfo(spell.name)
		return itemName, "", itemTexture, 0, false, 0, 0, 0, 0
	else
		return GetSpellInfo(spell.name)
	end
end

local function SpellTexture(curbar)
	local texture
	if curbar.specialcheck then
		for anothername, buffname in pairs(curbar.specialcheck) do
			if UnitBuff("player", buffname) then
				_, _, texture = GetSpellInfo(anothername)
				return texture
			end
		end
	end
	_, _, texture = GetInfo(curbar)
	return texture
end

local function UpdateAllPoints()
  	local prevframe
	for _, spell in pairs(barcfg.spells) do
		local name = spell.name
		local curbar = bar[name]
		if curbar:IsShown() then
  			if prevframe then
				curbar:SetPoint("TOP", prevframe, "BOTTOM", 0, -barcfg.buttonspacing)
				prevframe = curbar
  			else
				curbar:SetPoint("TOP", "rABS_CDBar", "TOP", 0, -barcfg.buttonspacing)
				prevframe = curbar
  			end
		end
	end	
end

local function UpdateBarsPos()
	if #(barspos) > 0 then
		local prevframe
		for i,v in pairs(barspos) do
			v:ClearAllPoints()
			if i == 1 then
				v:SetPoint("TOPLEFT", "rABS_CDBar", "TOPLEFT", 0, -barcfg.buttonspacing)
				prevframe = v
			else
				v:SetPoint("TOP", prevframe, "BOTTOM", 0, -barcfg.buttonspacing)
				prevframe = v
			end					
		end	 
	end
end 

local function DellBar(self)
	for i,v in pairs(barspos) do
		if v == self then 
			tremove(barspos, i)
			break 
		end
	end
end
  
local function AddBar(self,  endtime)
	if tContains(barspos, self) then
		DellBar(self)
	end
	self.stopped = false
	if self.alphaOut:IsPlaying() then self.alphaOut:Stop() end
	if #(barspos) == 0 then	
		self:SetPoint("TOPLEFT", "rABS_CDBar", "TOPLEFT", 0, -barcfg.buttonspacing)
		tinsert(barspos, self)
	else
		local insert = false
		local loctime =  endtime - GetTime()
		for i,v in pairs(barspos) do
			if v.lastTime and loctime > v.lastTime then
				tinsert(barspos, i, self)
				insert = true
				break
			end						
		end
		if not insert then
			tinsert(barspos, self)
		end
	end
end

local function SetTextTime(self, ShowText, endtime)
	if ShowText then
		self.text:Show()
		local loctime = endtime - GetTime()
		if self.statusbar then
			self.statusbar:SetValue(loctime)
		end
		if not self.lastTime then self.lastTime = loctime + 1 end
		if (self.lastTime - loctime > 0.1) or (self.lastTime < loctime) then
			if loctime > 60 then
				local sektime = math.floor(mod(loctime, 60))
				self.text:SetText(tostring(math.floor((loctime)/60))..":"..tostring(math.floor(sektime/10))..tostring(math.floor(mod(sektime, 10))))
				self.lastTime = loctime
			else
				self.text:SetText(tostring(math.floor(loctime)).."."..tostring(math.floor(mod(loctime*10, 10))))
				self.lastTime = loctime
			end
			if loctime < 0.1 and self.statusbar then
				self.statusbar:SetValue(0)
				if self:IsShown() and not self.alphaOut:IsPlaying() then
					self.alphaOut:Play()	
					self.stopped = true			
				end
				self.text:Hide()	
				self.lastTime = nil				
			end		
		end
	else
		self.lastTime = nil
		self.text:Hide()
		self.text:SetText("")
	end
end
local function CheckCooldown(self, start, duration, hasCooldown)
	local endtime = start + duration
	if self.cd then
		if not duration then
			if self.cd:IsShown() and not self.shinywheee:IsShown() then
				self.shinywheee:Show()				
			end
	    	self.cd:Hide() 
			self.text:Hide()
			self.gcd = false
		else			
        	if ( duration > 0 and start and (not self.cd:IsShown() or (self.gcd and duration > 2.5))) then
			    --print(start + duration, GetTime(), hasCooldown)
				if duration <= 2.5 then
					self.gcd = true
				end
	    		self.cd:SetCooldown(start, duration)
	    		self.cd:Show()
				self.lastTime = nil
     	    	self.start = start 
        	elseif (not (duration > 0 and start)) then 
				if self.cd:IsShown() and not self.shinywheee:IsShown() then
					self.shinywheee:Show()				
				end	    
	    		self.cd:Hide()
				self.gcd = false 
			elseif (self.start ~= start) then
	    		self.cd:SetCooldown(start, duration)
	    		self.cd:Show()
     	    	self.start = start 
				self.lastTime = nil
        	end
			SetTextTime(self, (duration > 0 and start), endtime)
		end	
	elseif self.statusbar then
		if hasCooldown == 1 and start > 0  then		
        	if ( duration > 2.5 and not self:IsShown() and (not RuneCheck or RuneCheck(self.name, endtime)) ) then
				AddBar(self, endtime)
				UpdateBarsPos()	
				self.statusbar:SetMinMaxValues(0, duration)
				self.statusbar:SetValue(duration)		
	    		self:Show()
     	    	self.endtime =  endtime
			elseif ( duration > 2.5 and self. endtime ~= endtime and (not RuneCheck or RuneCheck(self.name, endtime)) ) then
				AddBar(self, endtime)
				UpdateBarsPos()
				self.statusbar:SetMinMaxValues(0, duration)  
				self.statusbar:SetValue(duration)  			
				self:Show()
     	    	self.endtime =  endtime
				self.lastTime = nil
        	end
			SetTextTime(self, (self:IsShown() and not self.stopped), endtime)
		else
			self.statusbar:SetValue(0)
			if self:IsShown() and not self.alphaOut:IsPlaying() then
				self.alphaOut:Play()	
				self.stopped = true			
			end
			self.text:Hide()
			self.lastTime = nil
		end
	end
end
local function OnUpdate(self)
	local texture = SpellTexture(self)
	if not texture and self:IsShown() then
		self:Hide()
		UpdateAllPoints()
	elseif texture and not self:IsShown() then
		self:Show()
		UpdateAllPoints()
	end
	if texture ~= self.texture then
		self.icon:SetTexture(texture)
		self.texture = texture			
	end
	if self.cd or self.statusbar then
		local start, duration, hasCooldown  = GetCooldown(self)
		CheckCooldown(self, start, duration, hasCooldown)
	end
end

local function OnUpdateAll(self)
	for _, spell in pairs(barcfg.spells) do
		local name = spell.name
		local start, duration, hasCooldown = GetCooldown(spell)
		if duration and (duration > 2.5) and not bar[name]:IsShown() then OnUpdate(bar[name]) end 
	end	
end

local function BuildFrames()
	for _, spell in pairs(barcfg.spells) do
		local name = spell.name
  		bar[name] = CreateFrame("Frame", nil, rABS_CDBar)
		bar[name].stopped = false	
  		bar[name]:SetHeight(barcfg.buttonsize) 		
		if barcfg.bartype == "ICONS" then
			bar[name]:SetPoint("TOP", "rABS_CDBar", "TOP", 0, -barcfg.buttonspacing)
			bar[name]:SetWidth(barcfg.buttonsize)
		elseif barcfg.bartype == "STATUSBAR" then
  			bar[name]:SetPoint("TOPLEFT", "rABS_CDBar", "TOPLEFT", 0, -5)
			bar[name]:SetWidth(barcfg.buttonsize + barcfg.statusbarsize)
		end
  		bar[name].icon = bar[name]:CreateTexture(nil, "BORDER")
  		bar[name].icon:SetPoint('TOPLEFT',bar[name],'TOPLEFT', barcfg.border, -barcfg.border)
  		bar[name].icon:SetPoint('BOTTOMRIGHT',bar[name],'BOTTOMLEFT', barcfg.buttonsize - barcfg.border, barcfg.border) 
  		bar[name].icon:SetTexCoord(0.1,0.9,0.1,0.9)
  		if barcfg.bartype == "ICONS" then
			bar[name].cd = CreateFrame("Cooldown", nil, bar[name])
  			bar[name].cd:SetAllPoints(bar[name].icon)
			bar[name].text = bar[name].cd:CreateFontString(nil, 'OVERLAY') 
			bar[name].text:SetFont("Fonts\\ARIALN.TTF", barcfg.textsize)
			bar[name].text:SetShadowOffset(0,-2)
  			bar[name].text:SetJustifyH('LEFT')
  			bar[name].text:SetTextColor(0, 1, 0, 1)
  			bar[name].text:SetPoint('BOTTOM', bar[name].cd,'BOTTOM', 0, 1)
		elseif barcfg.bartype == "STATUSBAR" then
  			bar[name].statusbar = CreateFrame('StatusBar', nil, bar[name]) 
  			bar[name].statusbar:SetPoint('TOPLEFT',bar[name],'TOPLEFT', barcfg.buttonsize, -barcfg.border)
  			bar[name].statusbar:SetPoint('BOTTOMRIGHT',bar[name],'BOTTOMRIGHT', -barcfg.border, barcfg.border)
  			bar[name].statusbar:SetBackdropColor(0.18,0.18,0.18, 0.8)
  			bar[name].statusbar:SetStatusBarTexture(statusbar) 
			local color = cfg.classcolor
  			bar[name].statusbar:SetStatusBarColor(color.r, color.g, color.b)
			bar[name].text = bar[name].statusbar:CreateFontString(nil, 'OVERLAY')
			bar[name].text:SetFont(cfg.font, barcfg.textsize) 
			bar[name].text:SetShadowOffset(1,-1)
  			bar[name].text:SetJustifyH('RIGHT')
  			bar[name].text:SetPoint('RIGHT', bar[name].statusbar,'RIGHT', -2, 0)
			bar[name].text2 = bar[name].statusbar:CreateFontString(nil, 'OVERLAY') 
  			bar[name].text2:SetFont(cfg.font, barcfg.textsize)
  			bar[name].text2:SetShadowOffset(1,-1)
  			bar[name].text2:SetJustifyH('LEFT')
  			bar[name].text2:SetPoint('LEFT', bar[name].statusbar,'LEFT', 2, 0)
			bar[name].text2:SetPoint('RIGHT', bar[name].statusbar,'RIGHT', -30, 0)
  			bar[name].text2:SetText(name)	
		end
		bar[name].text:Hide()
  		bar[name].text:SetText("")
  		bar[name].iconBG = bar[name]:CreateTexture(nil, "BACKGROUND")
  		bar[name].iconBG:SetAllPoints(bar[name])
  		bar[name].iconBG:SetTexture(0, 0, 0, 0.4)
		bar[name].name = name
		if spell.item then
			bar[name].item = spell.item
		end
		bar[name].specialcheck = spell.addithions
		bar[name].texture = SpellTexture(bar[name])
		if not bar[name].texture then bar[name]:Hide() end
  		bar[name].icon:SetTexture(bar[name].texture)
		if barcfg.bartype == "STATUSBAR" then
			local anim = bar[name]:CreateAnimationGroup()
			local alphaOut = anim:CreateAnimation("Alpha")
			alphaOut:SetChange(-1)
			alphaOut:SetDuration(3)
			alphaOut:SetOrder(1)
			anim:SetScript("OnFinished", function() 
				DellBar(bar[name])
				UpdateBarsPos() 
		 		if (bar[name].stopped and bar[name]:IsShown()) then bar[name]:Hide() end
			end)

			bar[name].alphaOut = anim
			
			bar[name]:Hide()
		elseif barcfg.bartype == "ICONS" then
			local shinywheee = CreateFrame("Frame", nil, bar[name])
			shinywheee:SetAllPoints()
			shinywheee:SetAlpha(0)
			shinywheee:Hide()
				
			local shine = shinywheee:CreateTexture(nil, "OVERLAY")
			shine:SetAllPoints()
			shine:SetPoint("CENTER")
			shine:SetTexture("Interface\\Cooldown\\star4.blp")
			shine:SetBlendMode("ADD")

			local anim = shinywheee:CreateAnimationGroup()
			local anim2 = shinywheee:CreateAnimationGroup()
			local alphaIn = anim:CreateAnimation("Alpha")
			alphaIn:SetChange(0.4)
			alphaIn:SetDuration(0.6)
			alphaIn:SetOrder(1)
			local rotateIn = anim:CreateAnimation("Rotation")
			rotateIn:SetDegrees(-150)
			rotateIn:SetDuration(1)
			rotateIn:SetOrder(1)
			local scaleIn = anim:CreateAnimation("Scale")
			scaleIn:SetScale(2, 2)
			scaleIn:SetOrigin("CENTER", 0, 0)
			scaleIn:SetDuration(0.6)
			scaleIn:SetOrder(1)
			local alphaOut = anim2:CreateAnimation("Alpha")
			alphaOut:SetChange(-0.4)
			alphaOut:SetDuration(0.4)
			alphaOut:SetOrder(1)
			alphaOut:SetStartDelay(0.6)
			local scaleOut = anim2:CreateAnimation("Scale")
			scaleOut:SetScale(-2, -2)
			scaleOut:SetOrigin("CENTER", 0, 0)
			scaleOut:SetDuration(0.4)
			scaleOut:SetOrder(1)
			scaleOut:SetStartDelay(0.6)
			anim:SetScript("OnFinished", function() shinywheee:Hide() end)
			shinywheee:SetScript("OnShow", function() 
				anim:Play()
				anim2:Play()
			end)
			bar[name].shinywheee = shinywheee
		end
		bar[name]:SetScript("OnUpdate", OnUpdate)
	end
	if barcfg.bartype == "ICONS" then
		UpdateAllPoints()
		bar:RegisterEvent("SPELLS_CHANGED")
		bar:SetScript("OnEvent", function(self, event, ...)
			for _, spell in pairs(barcfg.spells) do
				local curbar = bar[spell.name]
				local texture = SpellTexture(curbar)
				if not texture and curbar:IsShown() then
					curbar:Hide()
					UpdateAllPoints()
				elseif texture and not curbar:IsShown() then
					curbar:Show()
					UpdateAllPoints()
				end
			end
  		end)
	elseif barcfg.bartype == "STATUSBAR" then
	    bar:RegisterEvent("SPELL_UPDATE_COOLDOWN")
		bar:SetScript("OnEvent", OnUpdateAll)
	end
end

local function Init()
  barcfg = cfg.bars.cdbar
  statusbar = cfg.statusbar
  
  bar = CreateFrame("Frame","rABS_CDBar",UIParent)
  bar:SetHeight(barcfg.buttonsize*(#(barcfg.spells))+barcfg.buttonspacing*(#(barcfg.spells) - 1))
  if barcfg.bartype == "ICONS" then
	 bar:SetWidth(barcfg.buttonsize)
  elseif barcfg.bartype == "STATUSBAR" then
     bar:SetWidth(barcfg.buttonsize + barcfg.statusbarsize)
  end
  bar:SetWidth(barcfg.buttonsize)
  bar:SetPoint(barcfg.pos.a1,point(barcfg.pos.af),barcfg.pos.a2,barcfg.pos.x,barcfg.pos.y)
  bar:SetHitRectInsets(-cfg.background.inset2, -cfg.background.inset2, -cfg.background.inset2, -cfg.background.inset2)
  
  if barcfg.testmode then
    bar:SetBackdrop(cfg.backdrop)
    bar:SetBackdropColor(1,0.8,1,0.6)
  end
  bar:SetScale(barcfg.barscale)
  
  if not barcfg.border then
  	barcfg.border = 1.5 
  	if barcfg.bartype == "ICONS" then
		barcfg.border = barcfg.border * 2
	end
  end

  if cfg.playerclass == "DEATHKNIGHT" then
		local runecd = {  -- Idea to fix come from coolline, updated to what we need.
			[GetSpellInfo(50977) or "Death Gate"] = {3, 4},
			[GetSpellInfo(43265) or "Death and Decay"] = {3, 4},
			[GetSpellInfo(42650) or "Army of the Dead"] = {3, 4},
			[GetSpellInfo(49222) or "Bone Shield"] = {3, 4},
			[GetSpellInfo(47476) or "Strangulate"] = {1, 2},
			[GetSpellInfo(51052) or "Anti-Magic Zone"] = {3, 4},
			[GetSpellInfo(49184) or "Howling Blast"] = {5, 6},
			[GetSpellInfo(48982) or "Rune Tap"] = {1, 2},
		}
		RuneCheck = function(name, endtime)
			if runecd[name] then 
				for i = 1,2 do
					local start, duration, runeReady = GetRuneCooldown(runecd[name][i])
					if runeReady or ((start + duration) < endtime)then return true end
				end
			else
				return true
			end
		end
  end
  
  BuildFrames()
end
LabelUI:AddInit(Init, "CDBar")